package cn.dduan.fool.design.pattern.behavior.command;

/**
 * 命令模式
 * <p>
 * 优点：
 * 1、降低了系统的耦合度
 * <p>
 * 缺点：
 * 1、导致某些系统有过多的具体命令类
 * <p>
 * 使用场景：
 * 1、需要将请求调用者和请求接收者解耦，使得调用者和接收者不直接交互
 * 2、系统需要在不同的时间指定请求、将请求排队和执行请求
 * 3、系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作
 * 4、系统需要将一组操作组合在一起，即支持宏命令
 *
 * @author dduan
 * @version 1.0
 * @date 2023/4/10
 */
public class CommandPattern {
    public static void main(String[] args) {
        Television tv = new Television();
        Command openCommand, closeCommand, changeCommand;

        openCommand = new OpenTvCommand(tv);
        closeCommand = new CloseTvCommand(tv);
        changeCommand = new ChangeChannelCommand(tv);

        Controller control = new Controller(openCommand, closeCommand, changeCommand);
        // 打开电视机
        control.open();
        // 换频道
        control.change();
        // 关闭电视机
        control.close();
    }
}

/**
 * Command命令接口，为所有的命令声明一个接口。所有的命令都应该实现它
 *
 * @author dduan
 * @version 1.0
 * @date 2023/4/10
 */
interface Command {
    public void execute();
}

/**
 * 电视机类
 *
 * @author dduan
 * @version 1.0
 * @date 2023/4/10
 */
class Television {
    public void open() {
        System.out.println("打开电视机......");
    }

    public void close() {
        System.out.println("关闭电视机......");
    }

    public void changeChannel() {
        System.out.println("切换电视频道......");
    }
}

/**
 * 遥控器类
 *
 * @author dduan
 * @version 1.0
 * @date 2023/4/10
 */
class Controller {
    private Command openTVCommand;
    private Command closeTVCommand;
    private Command changeChannelCommand;

    public Controller(Command openTvCommand, Command closeTvCommand, Command changeChannelCommand) {
        this.openTVCommand = openTvCommand;
        this.closeTVCommand = closeTvCommand;
        this.changeChannelCommand = changeChannelCommand;
    }

    /**
     * 打开电视剧
     */
    public void open() {
        openTVCommand.execute();
    }

    /**
     * 关闭电视机
     */
    public void close() {
        closeTVCommand.execute();
    }

    /**
     * 换频道
     */
    public void change() {
        changeChannelCommand.execute();
    }
}

/**
 * 遥控器功能：打开
 *
 * @author dduan
 * @version 1.0
 * @date 2023/4/10
 */
class OpenTvCommand implements Command {
    private Television tv;

    public OpenTvCommand(Television tv) {
        this.tv = tv;
    }

    @Override
    public void execute() {
        tv.open();
    }
}

/**
 * 遥控器功能：换频道
 *
 * @author dduan
 * @version 1.0
 * @date 2023/4/10
 */
class ChangeChannelCommand implements Command {
    private Television tv;

    public ChangeChannelCommand(Television tv) {
        this.tv = tv;
    }

    @Override
    public void execute() {
        tv.changeChannel();
    }
}

/**
 * 遥控器功能：关闭
 *
 * @author dduan
 * @version 1.0
 * @date 2023/4/10
 */
class CloseTvCommand implements Command {
    private Television tv;

    public CloseTvCommand(Television tv) {
        this.tv = tv;
    }

    @Override
    public void execute() {
        tv.close();
    }
}